#pragma once
#include "TAtlNPDispatch.h"

template <class T>
class TAtlNPVariant : public NPVariant
{
private:
	TAtlNPVariant()
	{
		m_hWnd = NULL;
		Clear();
	}
public:
	TAtlNPVariant(HWND hWnd)
	{
		m_hWnd = hWnd;
	}
	TAtlNPVariant(long ul, HWND hWnd)
	{
		m_hWnd = hWnd;
		*this = ul;
	}
	TAtlNPVariant(double d, HWND hWnd)
	{
		m_hWnd = hWnd;
		*this = d;
	}
	TAtlNPVariant(bool b, HWND hWnd)
	{
		m_hWnd = hWnd;
		*this = b;
	}
	TAtlNPVariant(const char* pstr, HWND hWnd)
	{
		m_hWnd = hWnd;
		*this = pstr;
	}
	TAtlNPVariant(NPVariant& npVar, HWND hWnd)
	{
		m_hWnd = hWnd;
		*this = npVar;
	}
	TAtlNPVariant(VARIANT& var, HWND hWnd)
	{
		m_hWnd = hWnd;
		*this = var;
	}
	~TAtlNPVariant()
	{
		Clear();
	}
private:
	HWND		m_hWnd;
public:
	bool Clear()
	{
		if(NPVARIANT_IS_OBJECT(*this))
		{
			IENPNFuncs.ReleaseObject(NPVARIANT_TO_OBJECT(*this));
		}
		else if(NPVARIANT_IS_STRING(*this))
		{
			IENPNFuncs.MemFree((void *)this->value.stringValue.UTF8Characters);
		}

		NULL_TO_NPVARIANT(*this);
		return true;
	}
public:
	TAtlNPVariant& operator = (long ul)
	{
		Clear();

		INT32_TO_NPVARIANT(ul, *this);
		return *this;
	}

	TAtlNPVariant& operator = (double d)
	{
		Clear();

		DOUBLE_TO_NPVARIANT(d, *this);
		return *this;
	}

	TAtlNPVariant& operator = (bool b)
	{
		Clear();

		BOOLEAN_TO_NPVARIANT(b, *this);
		return *this;
	}

	TAtlNPVariant& operator = (const char* pstr)
	{
		if( !Clear() )
			return *this;

		char*			pMem		= NULL;

		pMem = (char *)IENPNFuncs.MemAlloc((uint32_t)strlen(pstr)+1);
		if(NULL == pMem)
			return *this;
		memcpy(pMem, pstr, strlen(pstr)+1);
		STRINGZ_TO_NPVARIANT(pMem, *this);
		return *this;
	}

	TAtlNPVariant& operator = (NPVariant & var)
	{
		*((NPVariant *)this) = var;
	}
public:
	NPVariant		Detach()
	{
		NPVariant		var;

		var = *this;
		NULL_TO_NPVARIANT(*this);
		return var;
	}
public:
	TAtlNPVariant& operator = (VARIANT ievar)
	{
		switch(ievar.vt)
		{
		case VT_BOOL:
			*this = static_cast<bool>(VARIANT_FALSE != ievar.boolVal);
			break;
		case VT_I1:
		case VT_I2:
		case VT_I4:
		case VT_I8:
		case VT_UI1:
		case VT_UI2:
		case VT_UI4:
		case VT_UI8:
			*this = static_cast<long>(ievar.lVal);
			break;
		case VT_BSTR:
			*this = (LPCSTR)CW2A(ievar.bstrVal, CP_UTF8);
			break;
		case VT_R4:
		case VT_R8:
			*this = static_cast<double>(ievar.dblVal);
			break;
		case VT_NULL:
		case VT_EMPTY:
			Clear();
			break;
		case VT_DISPATCH:
			{
				NPP_t		nppt		= {0};
				NPObject*	pObject		= NULL;

				nppt.ndata = ievar.pdispVal;
				nppt.pdata = m_hWnd;
				pObject = IENPNFuncs.CreateObject(&nppt, (NPClass *)&TAtlNPDispatch<void>::Object);
				OBJECT_TO_NPVARIANT(pObject, *this);
			}
			break;
		default:
			ATLASSERT(FALSE);
			break;
		}

		return *this;
	}

	bool ToVARIANT(VARIANT* pVar)
	{
		VariantInit(pVar);

		if(NPVARIANT_IS_OBJECT(*this))
		{
			NPObject*		pObject		= NPVARIANT_TO_OBJECT(*this);

			if(NULL == pObject)
				return false;

			pVar->vt = VT_DISPATCH;
			((TAtlNPDispatch<void> *)pObject)->QueryInterface(IID_IDispatch, (void **)&pVar->pdispVal);
		}
		else if(NPVARIANT_IS_BOOLEAN(*this))
		{
			pVar->vt = VT_BOOL;
			pVar->boolVal = (FALSE != NPVARIANT_TO_BOOLEAN(*this))?VARIANT_TRUE:VARIANT_FALSE;
		}
		else if(NPVARIANT_IS_DOUBLE(*this))
		{
			pVar->vt = VT_R8;
			pVar->dblVal = NPVARIANT_TO_DOUBLE(*this);
		}
		else if(NPVARIANT_IS_INT32(*this))
		{
			pVar->vt = VT_I4;
			pVar->intVal = NPVARIANT_TO_INT32(*this);
		}
		else if(NPVARIANT_IS_STRING(*this))
		{
			LPCSTR		lpData		= NPVARIANT_TO_STRING(*this).UTF8Characters;

			pVar->vt = VT_BSTR;
			pVar->bstrVal = ::SysAllocString((LPCWSTR)(CA2W(lpData, CP_UTF8)));
		}
		else
		{
			return false;
		}

		return true;
	}

public:
	static TAtlNPVariant<T>* New(int nCount, HWND hWnd)
	{
		TAtlNPVariant<T>*	p;

		if(nCount < 1)
			return NULL;
		p = new TAtlNPVariant<T>[nCount];
		if(NULL == p)
			return NULL;
		for(int i = 0; i < nCount; i++)
		{
			p->m_hWnd = hWnd;
		}

		return p;
	}

	static void Delete(TAtlNPVariant<T>* p)
	{
		if(NULL == p)
			return;
		delete [] p;
	}
};

typedef TAtlNPVariant<void>		CAtlNPVariant;

